home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
cpp_libs
/
varia
/
rpc.lha
/
dynload
/
loader.cxx
next >
Wrap
C/C++ Source or Header
|
1993-08-08
|
25KB
|
1,088 lines
// Copyright (C) 1990 by Glenn Gribble; all rights are reserved.
// This program may be used for any purposes including inclusion in
// for profit programs. If the source is copied, the copyright notice
// must be included. Please send bug fixes/reports to glenn@synaptics.com
// This program is distributed without any warranty.
// %W% %G%
static char sccsid[] = "%W% %G%";
#include <sys/types.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <osfcn.h>
#include <fcntl.h>
#include <a.out.h>
#include <strings.h>
#include <memory.h>
#include <link.h>
#include <stdarg.h>
#define SYNAPTICS 1
#undef SYNAPTICS
#ifdef SYNAPTICS
# include <local/loader.h>
# include <local/loaderPrivate.h>
#else
# include "loader.h"
# include "loaderPrivate.h"
#endif
#if sun4
typedef reloc_info_sparc reloc_info_type;
#endif
#if sun3
typedef reloc_info_68k reloc_info_type;
#endif
symTable* symTable::top = NULL;
int d_all = 0;
int d_relocation = 0;
int d_execs = 1;
int d_ctors = 1;
int d_symbols = 1;
// Return an open fd to /dev/zero
int dev_zero()
{
static int ZERO = -1;
if (ZERO == -1)
ZERO = open("/dev/zero", O_RDONLY);
return ZERO;
}
void segment::setProt(int newProt)
{
if (mprotect((caddr_t)_data, _len, newProt) != 0) {
perror("mprotect");
} else {
_prot = newProt;
}
}
void segment::unmap()
{
if (_data != NULL)
if (munmap((caddr_t)_data, _len) != 0)
perror("setment::munmap");
}
segment::segment(int l, int p)
{
_prot = p;
_len = l;
if (_len == 0) {
_data = NULL;
} else {
_data = (memptr)mmap(0, _len, _prot, MAP_PRIVATE, dev_zero(), 0);
if ( int(_data) == -1 ) {
perror("segment::ctor:mmap");
fprintf(stderr,"_len=%d, _prot=%d\n", _len, _prot);
_data = NULL;
}
}
}
void printLong(nlist& N)
{
const char *sn = N.n_un.n_name;
if (sn == NULL) sn = "NO-NAME";
int X = N.n_type & 0x1;
char kn[20];
switch (N.n_type & ~0x1) {
case N_TEXT:
strcpy(kn, X ? "TEXT" : "text");
break;
case N_DATA:
strcpy(kn, X ? "DATA" : "data");
break;
case N_BSS:
strcpy(kn, X ? "BSS" : "bss");
break;
default:
sprintf(kn,"0x%0X",N.n_type);
break;
}
printf("%-16s (%4s) %08X\n", sn, kn, N.n_value);
fflush(stdout);
}
segment mapSome(int fd, int offset, int length,
int prot = PROT_READ|PROT_EXEC|PROT_WRITE,
int flag = MAP_PRIVATE)
{
int pageSize = getpagesize();
int realOffset = offset & ~(pageSize-1);
int inPageOffset = offset - realOffset;
int realLength = length + (offset-realOffset);
memptr tmp = (memptr)mmap(0, realLength, prot, flag, fd, realOffset);
if ( int(tmp) == -1 ) {
perror("mmap");
return NULL;
}
return segment(tmp + inPageOffset, length, prot);
}
segment copySomeI(int fd, int offset,
int length, int extra)
{
segment s(length+extra, PROT_READ|PROT_EXEC|PROT_WRITE);
if (s.data() == NULL) return s;
lseek(fd, offset, L_SET);
int len = read(fd, s.data(), (int)length);
if (len != (int)length) {
perror("read");
return NULL;
}
return s;
}
inline segment copySome(int fd,
unsigned long offset,
unsigned long length,
unsigned long extra = 0)
{
return copySomeI(fd, (int)offset, (int)length, (int)extra);
}
// Change all n_strx entries to point to the actual string (n_name)
void symTable::fixup(register char *strBase)
{
register int quick = 0;
register nlist *nl = realSymbols;
register int nnl = numRealSymbols;
for (register int i=0; i<nnl; i++) {
register nlist& N = nl[i];
register long offset = N.n_un.n_strx;
if (offset != 0)
N.n_un.n_name = strBase + offset;
else
N.n_un.n_name = "no-name";
if ( (N.n_type & N_EXT) == N_EXT ) quick++;
}
// Now we know how many external symbols there are, so we can allocate
// the 'quick' array
typedef nlist *nlistptr;
numQuickSymbols = quick;
quickSymbols = new nlistptr[numQuickSymbols];
quick = 0;
register nlist **qs = quickSymbols;
for (i=0; i<nnl; i++) {
register nlist* N = nl+i;
if ( (N->n_type & N_EXT) == N_EXT ) qs[quick++] = N;
}
}
nlist *symTable::lookup(register const char *name)
{
register nlist **qs = quickSymbols;
for (register int i = 0; i<numQuickSymbols; i++) {
nlist* N = qs[i];
if (strcmp(N->n_un.n_name, name) == 0) return N;
}
return NULL;
}
nlist *symTable::value(register const char *name)
{
register nlist *v = lookup(name);
if (v != NULL)
return value(v);
if (prev == NULL)
return NULL;
return prev->value(name);
}
nlist *symTable::value(int indx)
{
register nlist *v = realSymbols+indx;
return value(v);
}
nlist *symTable::value(register nlist *v)
{
register nlist& N = *v;
switch (N.n_type) {
case N_ABS + N_EXT:
case N_SET:
break;
case N_UNDF + N_EXT:
// Undefined symbol, try to define it from lower levels
nlist *v2;
if (prev == NULL || (v2 = prev->value(v->n_un.n_name)) == NULL) {
error("%s: symbol undefined", v->n_un.n_name);
return NULL;
}
N.n_type = v2->n_type;
N.n_value= v2->n_value;
break;
case N_TEXT + N_EXT:
N.n_value += text_offset;
N.n_type = N_SET;
break;
case N_DATA + N_EXT:
case N_BSS + N_EXT:
if (data_offset == -1) {
warn("%s mapped to data in illegal data segment", v->n_un.n_name);
N.n_value += text_offset;
} else
N.n_value += data_offset;
N.n_type = N_SET;
break;
default:
warn("%s mapped to funny type symbol",N.n_un.n_name);
printLong(N);
break;
}
return v;
}
void symTable::printAll()
{
for (register int i = 0; i<numRealSymbols; i++)
printLong(realSymbols[i]);
}
symTable::~symTable()
{
delete FileName;
}
symTable::symTable(const char *fn, bool loadWholeFile)
{
FileName = new char[strlen(fn)+1];
strcpy(FileName, fn);
data_offset = 0;
text_offset = 0;
good = TRUE;
prev = symTable::top;
if (loadWholeFile) {
if (!copyin()) {
error("%s: could not copyin", fileName());
good = FALSE;
}
} else {
if (!mapit()) {
error("%s: could not mapit", fileName());
good = FALSE;
}
}
if (good)
symTable::top = this;
}
symTable *loadSymTable(const char *fn, bool loadWholeFile)
{
symTable *st = new symTable(fn, loadWholeFile);
if (st->good)
return st;
delete st;
return NULL;
}
bool symTable::mapit()
{
int fd = open(fileName(), O_RDONLY);
if (fd < 0) {
perror(fileName());
return FALSE;
}
if (read(fd, &E, sizeof(E)) != sizeof(E)) {
perror(fileName());
close(fd);
return FALSE;
}
if (N_BADMAG(E)) {
error("Bad magic number for %s",fileName());
close(fd);
return FALSE;
}
int fileLength = (int) lseek(fd, 0, L_XTND);
lseek(fd, 0, 0);
if (debugExecs())
info("%s is %d bytes long", fileName(), fileLength);
int symbolOffset = (int) N_SYMOFF(E);
int symbolsAndStrings = fileLength - symbolOffset;
segment fbs = mapSome(fd, symbolOffset, symbolsAndStrings);
memptr fileBase = fbs.data();
if (debugExecs())
info("mapped symbols at $%X",int(fileBase));
if ( fileBase == NULL ) {
perror("mmap");
close(fd);
return FALSE;
}
//memptr textWhere = fileBase + N_TXTOFF(E);
//memptr dataWhere = fileBase + N_DATOFF(E);
//memptr trelWhere = fileBase + N_TRELOFF(E);
//memptr drelWhere = fileBase + N_DRELOFF(E);
memptr symWhere = fileBase;
memptr strWhere = fileBase + N_STROFF(E) - N_SYMOFF(E);
realSymbols = (nlist*) symWhere;
numRealSymbols = (int) E.a_syms / sizeof(nlist);
fixup( (char *) strWhere );
return TRUE;
}
const char *symbolNumToText(int symbolNum)
{
switch (symbolNum) {
case N_TEXT:
return "text-rel";
case N_DATA:
return "data-rel";
case N_UNDF:
return "undef-rel";
case N_ABS:
return "abs-rel";
case N_BSS:
return "bss-rel";
case N_COMM:
return "comm-rel";
case N_FN:
return "fn-rel";
case N_EXT:
return "ext-rel";
default:
return "unknown-symbol-num";
}
}
#ifdef sun3
bool symTable::doReloc(reloc_info_type *rl,
int relocSize,
register memptr seg)
{
bool failed = FALSE;
int numReloc = relocSize / sizeof(reloc_info_type);
for (int i = 0; i < numReloc; i++) {
register reloc_info_type& R = rl[i];
register long addMe = 0;
if (R.r_extern) {
// If external, then this is relative to an external symbol
nlist *nl = value(R.r_symbolnum);
if (nl != NULL)
addMe = nl->n_value;
else {
error("doReloc: undef symbol # %d", R.r_symbolnum);
failed = TRUE;
}
} else {
switch (R.r_symbolnum) {
case N_TEXT:
case N_DATA:
case N_BSS:
addMe = text_offset; // Same as data_offset
break;
default:
failed = TRUE;
error("doReloc: Don't understand %s",
symbolNumToText(R.r_symbolnum));
}
}
if (R.r_pcrel != 0) {
error("doReloc: Don't grok r_pcrel=%d", R.r_pcrel);
failed = TRUE;
}
if (R.r_baserel != 0) {
error("doReloc: Don't grok r_baserel=%d", R.r_baserel);
failed = TRUE;
}
if (R.r_jmptable != 0) {
error("doReloc: Don't grok r_pcrel=%d", R.r_pcrel);
failed = TRUE;
}
if (R.r_relative != 0) {
error("doReloc: Don't grok r_relative=%d", R.r_relative);
failed = TRUE;
}
switch (R.r_length) {
case 0:
*(char *)(seg+R.r_address) += (char )addMe;
break;
case 1:
*(short*)(seg+R.r_address) += (short)addMe;
break;
case 2:
*(long *)(seg+R.r_address) += (long )addMe;
break;
default:
error("doReloc: Don't grok r_length=%d",R.r_length);
failed = TRUE;
}
}
if (failed)
return FALSE;
else
return TRUE;
}
void symTable::showReloc(reloc_info_type *rl, int size, memptr seg)
{
int nreloc = size / sizeof(reloc_info_type);
for (int i = 0; i < nreloc; i++) {
reloc_info_type& R = rl[i];
const char *sym = "##?";
if (R.r_extern) {
nlist& N = realSymbols[R.r_symbolnum];
sym = N.n_un.n_name;
} else {
sym = symbolNumToText(R.r_symbolnum);
}
long value = -1;
switch (R.r_length) {
case 0:
value = *(char *)(seg+R.r_address);
break;
case 1:
value = *(short*)(seg+R.r_address);
break;
case 2:
value = *(long *)(seg+R.r_address);
break;
}
info("%4d = %08x %12s pcr:%d len:%d ex:%d br:%d jmp:%d rel:%d",
R.r_address, value,
sym, R.r_pcrel, R.r_length,
R.r_extern, R.r_baserel, R.r_jmptable,
R.r_relative);
}
}
#endif /* sun3 */
#ifdef sun4
const char *sparcRelocType(int ir)
{
reloc_type r = (reloc_type) ir;
switch (r) {
case RELOC_8:
return "RELOC_8";
case RELOC_16:
return "RELOC_16";
case RELOC_32:
return "RELOC_32";
case RELOC_DISP8:
return "RELOC_DISP8";
case RELOC_DISP16:
return "RELOC_DISP16";
case RELOC_DISP32:
return "RELOC_DISP32";
case RELOC_WDISP30:
return "RELOC_WDISP30";
case RELOC_WDISP22:
return "RELOC_WDISP22";
case RELOC_HI22:
return "RELOC_HI22";
case RELOC_22:
return "RELOC_22";
case RELOC_13:
return "RELOC_13";
case RELOC_LO10:
return "RELOC_LO10";
case RELOC_SFA_BASE:
return "RELOC_SFA_BASE";
case RELOC_SFA_OFF13:
return "RELOC_SFA_OFF13";
case RELOC_BASE10:
return "RELOC_BASE10";
case RELOC_BASE13:
return "RELOC_BASE13";
case RELOC_BASE22:
return "RELOC_BASE22";
case RELOC_PC10:
return "RELOC_PC10";
case RELOC_PC22:
return "RELOC_PC22";
case RELOC_JMP_TBL:
return "RELOC_JMP_TBL";
case RELOC_SEGOFF16:
return "RELOC_SEGOFF16";
case RELOC_GLOB_DAT:
return "RELOC_GLOB_DAT";
case RELOC_JMP_SLOT:
return "RELOC_JMP_SLOT";
case RELOC_RELATIVE:
return "RELOC_RELATIVE";
default:
return "RELOC_unknown";
}
}
typedef unsigned long ULONG;
bool symTable::doReloc(reloc_info_type *rl,
int relocSize,
register memptr seg)
{
bool failed = FALSE;
int nreloc = relocSize / sizeof(reloc_info_type);
for (int i = 0; i < nreloc; i++) {
register reloc_info_type& R = rl[i];
register long addMe = 0;
if (R.r_extern) {
nlist *nl = value(R.r_index);
if (nl != NULL)
addMe = nl->n_value;
else {
error("doReloc: undef symbol # %d", R.r_index);
failed = TRUE;
}
} else {
switch (R.r_index) {
case N_TEXT:
case N_DATA:
case N_BSS:
addMe = text_offset; // Same as data_offset
break;
default:
failed = TRUE;
error("doReloc: Don't understand %s",
symbolNumToText(R.r_index));
}
}
register memptr where = seg + R.r_address;
register ULONG value = addMe + R.r_addend;
register bool bad = FALSE; // Do I know how to process this?
switch (R.r_type) {
case RELOC_8:
bad = TRUE;
break;
case RELOC_16:
bad = TRUE;
break;
case RELOC_32: // Just set the value
*(ULONG*) where = value;
break;
case RELOC_DISP8:
bad = TRUE;
break;
case RELOC_DISP16:
bad = TRUE;
break;
case RELOC_DISP32:
bad = TRUE;
break;
case RELOC_WDISP30: // "Word Displacement", PC-REL, (shr by 2)
*(ULONG*) where |= (addMe-ULONG(where)) >> 2;
break;
case RELOC_WDISP22: // "Word Displacement", PC-REL, (shr by 2)
bad = TRUE;
break;
case RELOC_HI22: // High 22 bits of thingie, (shr by 10)
*(ULONG*) where |= value >> 10;
break;
case RELOC_22:
bad = TRUE;
break;
case RELOC_13:
bad = TRUE;
break;
case RELOC_LO10: // Low 10 bits of thingie, (just mask bits)
*(ULONG*) where |= value & 0x03FF;
break;
case RELOC_SFA_BASE:
bad = TRUE;
break;
case RELOC_SFA_OFF13:
bad = TRUE;
break;
case RELOC_BASE10:
bad = TRUE;
break;
case RELOC_BASE13:
bad = TRUE;
break;
case RELOC_BASE22:
bad = TRUE;
break;
case RELOC_PC10:
bad = TRUE;
break;
case RELOC_PC22:
bad = TRUE;
break;
case RELOC_JMP_TBL:
bad = TRUE;
break;
case RELOC_SEGOFF16:
bad = TRUE;
break;
case RELOC_GLOB_DAT:
bad = TRUE;
break;
case RELOC_JMP_SLOT:
bad = TRUE;
break;
case RELOC_RELATIVE:
bad = TRUE;
break;
default:
bad = TRUE;
break;
}
if (bad) {
failed = TRUE;
long value = *(long*) (seg + R.r_address);
error("Could not process %s", sparcRelocType(R.r_type));
const char *sym = "";
if (R.r_extern)
sym = realSymbols[R.r_index].n_un.n_name;
else
sym = symbolNumToText(R.r_index);
info("%4d : %08x +%08x (%6d) %16s %s%s",
R.r_address, value, R.r_addend, R.r_addend,
sym, sparcRelocType(R.r_type), bad ? " (bad)" : "");
}
}
return !failed;
}
#if 0
enum reloc_type
{
RELOC_8, RELOC_16, RELOC_32, /* simplest relocs */
RELOC_DISP8, RELOC_DISP16, RELOC_DISP32, /* Disp's (pc-rel) */
RELOC_WDISP30,RELOC_WDISP22, /* SR word disp's */
RELOC_HI22, RELOC_22, /* SR 22-bit relocs */
RELOC_13, RELOC_LO10, /* SR 13&10-bit relocs*/
RELOC_SFA_BASE,RELOC_SFA_OFF13, /* SR S.F.A. relocs */
RELOC_BASE10, RELOC_BASE13, RELOC_BASE22, /* base_relative pic */
RELOC_PC10, RELOC_PC22, /* special pc-rel pic*/
RELOC_JMP_TBL, /* jmp_tbl_rel in pic */
RELOC_SEGOFF16, /* ShLib offset-in-seg*/
RELOC_GLOB_DAT, RELOC_JMP_SLOT, RELOC_RELATIVE, /* rtld relocs */
};
struct reloc_info_sparc /* used when header.a_machtype == M_SPARC */
{
unsigned long int r_address; /* relocation addr (offset in segment)*/
unsigned int r_index :24; /* segment index or symbol index */
unsigned int r_extern : 1; /* if F, r_index==SEG#; if T, SYM idx */
int : 2; /* <unused> */
enum reloc_type r_type : 5; /* type of relocation to perform */
long int r_addend; /* addend for relocation value */
};
#endif /* 0 */
void symTable::showReloc(reloc_info_type *rl, int size, memptr seg)
{
int nreloc = size / sizeof(reloc_info_type);
for (int i = 0; i < nreloc; i++) {
reloc_info_type& R = rl[i];
const char *sym = (R.r_extern)
? realSymbols[R.r_index].n_un.n_name
: symbolNumToText(R.r_index);
bool bad = FALSE; // Do I know how to process this?
switch (R.r_type) {
case RELOC_8:
bad = TRUE;
break;
case RELOC_16:
bad = TRUE;
break;
case RELOC_32:
break;
case RELOC_DISP8:
bad = TRUE;
break;
case RELOC_DISP16:
bad = TRUE;
break;
case RELOC_DISP32:
bad = TRUE;
break;
case RELOC_WDISP30: // "Word Displacement", PC-REL, (shr by 2)
break;
case RELOC_WDISP22: // "Word Displacement", PC-REL, (shr by 2)
bad = TRUE;
break;
case RELOC_HI22: // High 22 bits of thingie, (shr by 10)
break;
case RELOC_22:
bad = TRUE;
break;
case RELOC_13:
bad = TRUE;
break;
case RELOC_LO10: // Low 10 bits of thingie, (just mask bits)
break;
case RELOC_SFA_BASE:
bad = TRUE;
break;
case RELOC_SFA_OFF13:
bad = TRUE;
break;
case RELOC_BASE10:
bad = TRUE;
break;
case RELOC_BASE13:
bad = TRUE;
break;
case RELOC_BASE22:
bad = TRUE;
break;
case RELOC_PC10:
bad = TRUE;
break;
case RELOC_PC22:
bad = TRUE;
break;
case RELOC_JMP_TBL:
bad = TRUE;
break;
case RELOC_SEGOFF16:
bad = TRUE;
break;
case RELOC_GLOB_DAT:
bad = TRUE;
break;
case RELOC_JMP_SLOT:
bad = TRUE;
break;
case RELOC_RELATIVE:
bad = TRUE;
break;
default:
bad = TRUE;
break;
}
/*
opcode rightShift bytesize bitsize
RELOC_8, 0 0 8
RELOC_16, 0 1 16
RELOC_32, 0 2 32
RELOC_DISP8, 0 0 8
RELOC_DISP16, 0 1 16
RELOC_DISP32, 0 2 32
RELOC_WDISP30, 2 2 30
RELOC_WDISP22, 2 2 22
RELOC_HI22, 10 2 22
RELOC_22, 0 2 22
RELOC_13, 0 2 13
RELOC_LO10, 0 2 10
RELOC_SFA_BASE, 0 2 32
RELOC_SFA_OFF13 0 2 32
RELOC_BASE10, 0 2 16
RELOC_BASE13,
RELOC_BASE22,
RELOC_PC10,
RELOC_PC22,
RELOC_JMP_TBL,
RELOC_SEGOFF16,
RELOC_GLOB_DAT,
RELOC_JMP_SLOT,
RELOC_RELATIVE,
*/
long value = *(long*) (seg + R.r_address);
info("%4d : %08x +%08x (%6d) %16s %s%s",
R.r_address, value, R.r_addend, R.r_addend,
sym, sparcRelocType(R.r_type), bad ? " (bad)" : "");
}
}
#endif /* sun4 */
// This procedure calls the procedure at v. The main reason to have
// this be a separate procedure is for debugging (stop in callit)
void callit(long v)
{
typedef void (*procedure)();
procedure ctor = (procedure)v;
(*ctor)();
}
// Map in a file and think about it
bool symTable::copyin()
{
int fd = open(fileName(), O_RDONLY);
if (fd<0) {
perror(fileName());
return FALSE;
}
int fileLength = (int)lseek(fd, 0, L_XTND);
lseek(fd, 0, 0);
if (debugExecs())
info("%s is %d bytes long", fileName(), fileLength);
if (read(fd, &E, sizeof(E)) != sizeof(E)) {
perror(fileName());
close(fd);
return FALSE;
}
if (N_BADMAG(E)) {
error("Bad magic number for %s",fileName());
close(fd);
return FALSE;
}
if (E.a_magic != OMAGIC) {
error("Bad magic number for %s, %o. Need %o",
fileName(), E.a_magic, ZMAGIC);
close(fd);
return FALSE;
}
segment text = copySome(fd, N_TXTOFF(E), E.a_text+E.a_data, E.a_bss);
memptr data = text.data() + E.a_text;
memptr bss = data + E.a_data;
segment trel = copySome(fd, N_TRELOFF(E), E.a_trsize);
segment drel = copySome(fd, N_DRELOFF(E), E.a_drsize);
segment syms = copySome(fd, N_SYMOFF(E), E.a_syms);
segment strs = copySome(fd, N_STROFF(E), fileLength-N_STROFF(E));
strs.setProt(PROT_READ);
close(fd);
realSymbols = (nlist*) syms.data();
numRealSymbols = (int)E.a_syms / sizeof(nlist);
fixup((char*) strs.data());
text_offset = (long)text.data();
data_offset = text_offset;
reloc_info_type *TR = (reloc_info_type*) trel.data();
reloc_info_type *DR = (reloc_info_type*) drel.data();
if (debugRelocation()) {
info("Text relocation");
showReloc(TR, (int) E.a_trsize, text.data());
}
if (!doReloc(TR, (int) E.a_trsize, text.data())) {
error("could not relocate text segment");
trel.unmap();
drel.unmap();
return FALSE;
}
if (debugRelocation()) {
info("After text relocation");
showReloc(TR, (int) E.a_trsize, text.data());
}
if (debugRelocation()) {
info("Data relocation");
showReloc(DR, (int) E.a_drsize, data);
}
if (!doReloc(DR, (int) E.a_drsize, data)) {
error("could not relocate data segment");
trel.unmap();
drel.unmap();
return FALSE;
}
if (debugRelocation()) {
info("After data relocation");
showReloc(DR, (int) E.a_drsize, data);
}
trel.unmap();
drel.unmap();
const char *constructorBase = "___sti__";
const int constructorBaseLen= strlen(constructorBase);
// Look for constructors and call them
for (int i=0; i<numRealSymbols; i++) {
nlist& N = realSymbols[i];
if (strncmp(constructorBase, N.n_un.n_name, constructorBaseLen) == 0) {
nlist *nl = value(i);
long v = nl->n_value;
if (debugConstructors())
info("Calling '%s' at $%X", N.n_un.n_name, v);
fflush(stdout);
fflush(stderr);
callit(v);
}
}
return TRUE;
}
bool loadSymbolChildren(link_map* l)
{
if (l == NULL) return TRUE;
if (!loadSymbolChildren(l->lm_next))
return FALSE;
symTable *st = loadSymTable(l->lm_name, FALSE);
if (st == NULL) {
error("loadSymbolChildren: could not create symTable");
return FALSE;
}
exec& E = *(exec*) l->lm_addr;
if (bcmp(&E, &st->E, sizeof(E)) != 0) {
error("loadSymbolChildren: execs do not match for %s",
l->lm_name);
return FALSE;
}
if (debugExecs())
info("Found exec for %s at %x", st->fileName(), &E);
st->text_offset = long(l->lm_addr) - N_TXTOFF(E);
st->data_offset = -1;
return TRUE;
}
bool openTables(const char *myFile)
{
// Check version of DYNAMIC structure
if (_DYNAMIC.ld_version > 3)
warn("DYNAMIC.ld_version = %d", _DYNAMIC.ld_version);
if (!loadSymbolChildren(_DYNAMIC.ld_un.ld_2->ld_loaded)) return FALSE;
if (loadSymTable(myFile, FALSE) == NULL)
return FALSE;
else
return TRUE;
}
long value(const char *symbol, int badValue)
{
nlist *nl = symTable::top->value(symbol);
if (nl == NULL) {
error("%s not found", symbol);
return badValue;
} else {
long v = nl->n_value;
if (debugSymbols())
info("Value of %s is %x", symbol, v);
return v;
}
}
const char *strchr(register const char *s, register char c)
{
for ( ; *s != c && *s != '\0'; s++);
if (*s == c)
return s;
else
return NULL;
}
// Return a pointer to an allocated string for the full pathname
// given just the argv[0] type name
const char *pathFind(const char *fileName, const char *path)
{
if (strchr(fileName, '/') != NULL) {
// fileName has a /, so it must be here
if (access(fileName, R_OK) < 0) {
perror(fileName);
return NULL;
}
return strdup(fileName);
}
const char *p = path;
char name[1024];
do {
// Find the first path element
const char *e = strchr(p, ':');
if (e == NULL) e = p+strlen(p);
strncpy(name, p, e-p);
name[e-p] = '\0';
p = e;
if (*p == ':') p++;
strcat(name, "/");
strcat(name, fileName);
// fprintf(stderr,"Looking for %s\n", name);
if (access(name, R_OK) == 0)
return strdup(name);
} while ( *p != '\0' );
return NULL;
}
static const char *baseFile = NULL;
void setArg0(const char *a0)
{
// Look everywhere in the path to find the file
const char *PATH = getenv("PATH");
if (PATH == NULL) {
error("setArg0: path is NULL?");
return;
}
baseFile = pathFind(a0, PATH);
if (baseFile == NULL)
error("Could not find %s in %s", a0, PATH);
info("setArg0: %s mapped to %s", a0, baseFile);
}
// Link in an object file
bool loadFile(const char *fileName)
{
if (symTable::top == NULL) {
if (baseFile == NULL) {
error("loadFile(%s): could not load, baseFile == NULL", fileName);
return FALSE;
}
if ( !openTables(baseFile) )
return FALSE;
}
if (symTable::top == NULL) {
error("loadFile: symTable::top == NULL, can't load");
return FALSE;
}
if (loadSymTable(fileName, TRUE) != NULL)
return TRUE;
else
return FALSE;
#if 0
#ifdef sun3
#endif /* sun3 */
#ifdef sun4
fprintf(stderr,"loadFile: Can't do that on sun4\n");
return FALSE;
#endif /* sun4 */
#endif
}